#include "cubemap_renderer.h"
#include "teflon/core/asset.h"

namespace teflon
{
    CubemapRenderer::CubemapRenderer()
    {
        // load shader
        std::map<teflon::ShaderType, std::string> shader_sources;
        std::string vspath = get_asset_path("shaders/cubemap.vs");
        std::string fspath = get_asset_path("shaders/cubemap.fs");
        shader_sources.insert(std::make_pair(teflon::ShaderType::Vertex, vspath));
        shader_sources.insert(std::make_pair(teflon::ShaderType::Fragment, fspath));
        shader = std::make_shared<ShaderProgram>(shader_sources);

        // set up simple quad
        setup_vertices();
    }

    CubemapRenderer::~CubemapRenderer()
    {
        // delete resiyrces
        glDeleteVertexArrays(1, &vao);
        glDeleteBuffers(1, &vbo);
    }

    void CubemapRenderer::Begin(const Environment3D& env)
    {
        shader->Bind();
        glm::mat4 view = env.camera->getViewMatrixOrigin();
        glm::mat4 proj = env.camera->getProjectionMatrix(env.window_width, env.window_height);

        shader->SetUniformMat4("V", view);
        shader->SetUniformMat4("P", proj);
        shader->SetTextureUniform("cube_texture", 0);

        glDepthMask(GL_FALSE);
        glDisable(GL_CULL_FACE);
    }

    void CubemapRenderer::Draw(const Cubemap& cm)
    {
        cm.Bind(0);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 36);

        cm.Unbind();
    }

    void CubemapRenderer::End()
    {
        glBindVertexArray(0);
    }

    void CubemapRenderer::setup_vertices()
    {
        float points[] = {
            -10.0f, 10.0f, -10.0f, -10.0f, -10.0f, -10.0f, 10.0f, -10.0f, -10.0f, 10.0f, -10.0f, -10.0f, 10.0f, 10.0f, -10.0f, -10.0f, 10.0f, -10.0f,
            -10.0f, -10.0f, 10.0f, -10.0f, -10.0f, -10.0f, -10.0f, 10.0f, -10.0f, -10.0f, 10.0f, -10.0f, -10.0f, 10.0f, 10.0f, -10.0f, -10.0f, 10.0f,
            10.0f, -10.0f, -10.0f, 10.0f, -10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, -10.0f, 10.0f, -10.0f, -10.0f,
            -10.0f, -10.0f, 10.0f, -10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, -10.0f, 10.0f, -10.0f, -10.0f, 10.0f,
            -10.0f, 10.0f, -10.0f, 10.0f, 10.0f, -10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f, -10.0f, 10.0f, 10.0f, -10.0f, 10.0f, -10.0f,
            -10.0f, -10.0f, -10.0f, -10.0f, -10.0f, 10.0f, 10.0f, -10.0f, -10.0f, 10.0f, -10.0f, -10.0f, -10.0f, -10.0f, 10.0f, 10.0f, -10.0f, 10.0f };

        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, 3 * 36 * sizeof(GLfloat), &points, GL_STATIC_DRAW);

        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    }
}
